package com.mybatis.service.impl;

import com.mybatis.constant.Constants;
import com.mybatis.dto.request.CodeGenerationParam;
import com.mybatis.dto.request.DatabaseParam;
import com.mybatis.exception.CommonException;
import com.mybatis.message.Result;
import com.mybatis.message.ReturnResult;
import com.mybatis.service.GeneratorService;
import com.mybatis.strategy.DatabaseStrategy;
import com.mybatis.template.AbstractGeneratorTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @desc: 代码生成相关接口实现类
 * @projectName: mybatis-generator-parent
 * @author: xhs
 * @date: 2023-7-22 022 15:18
 * @version: JDK 1.8
 */
@Slf4j
@Service
public class GeneratorServiceImpl implements GeneratorService {

    @Resource
    private Map<String, DatabaseStrategy> databaseStrategyMap;
    @Resource
    private Map<String, AbstractGeneratorTemplate> generatorTemplateMap;

    /**
     * 数据库连接测试
     *
     * @param databaseParam 数据库连接入参
     * @return ReturnResult
     */
    @Override
    public ReturnResult<Object> databaseConnection(DatabaseParam databaseParam) {
        DatabaseStrategy databaseStrategy = databaseStrategyMap.get(databaseParam.getDataBaseType());
        Connection connection = databaseStrategy.databaseConnection(databaseParam);
        try {
            if (!connection.isClosed()) {
                return ReturnResult.build(Result.DATABASE_CONNECTION_SUCCESS);
            }
        } catch (SQLException e) {
            throw new CommonException(e.getMessage());
        } finally {
            try {
                if (!connection.isClosed()) {
                    // 关闭数据库连接
                    connection.close();
                    log.info("{}{}数据库连接已关闭{}", Constants.START, databaseParam.getDataBaseType(), Constants.END);
                }
            } catch (SQLException e) {
                throw new CommonException(e.getMessage());
            }
        }
        return ReturnResult.build(Result.DATABASE_CONNECTION_ERROR);
    }

    /**
     * 获取数据库所有表名称
     *
     * @param databaseParam 数据库连接入参
     * @return ReturnResult
     */
    @Override
    public ReturnResult<Object> getTableNameList(DatabaseParam databaseParam) {
        DatabaseStrategy databaseStrategy = databaseStrategyMap.get(databaseParam.getDataBaseType());
        List<String> tableList = databaseStrategy.getTableList(databaseParam);
        return ReturnResult.success().setData(tableList);
    }

    /**
     * 代码生成
     *
     * @param codeGenerationParam 代码生成入参
     * @return ReturnResult
     */
    @Override
    public ReturnResult<Object> codeGeneration(CodeGenerationParam codeGenerationParam) {
        AbstractGeneratorTemplate template = generatorTemplateMap.get(codeGenerationParam.getOrmType());
        return template.generatorCode(codeGenerationParam);
    }

    /**
     * 下载生成的代码
     *
     * @param fileUrl  文件路径
     * @param response response
     */
    @Override
    public void downloadCode(HttpServletResponse response, String fileUrl) {
        try {
            File file = new File(fileUrl);
            // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(Files.newInputStream(Paths.get(fileUrl)));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            response.addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream;charset=utf-8");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (IOException e) {
            throw new CommonException(e.getMessage());
        }
    }
}
